home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 17 / AMIGAplus Sonderheft 17 (1999)(ICP)(DE)[!].iso / dsound / source.lha / DSound.c < prev    next >
C/C++ Source or Header  |  1994-07-18  |  28KB  |  1,051 lines

  1.  
  2. /**************************************************************************/
  3. /*                 DSound V1.50                  */
  4. /*    Copyright 1991-1994 by Dave Schreiber, All Rights Reserved.      */
  5. /*                                      */
  6. /* To compile with SAS/C version 6, type:                  */
  7. /*    smake                                  */
  8. /*                                      */
  9. /* Revision history:                              */
  10. /*    V1.50  - Fixed a bug that caused DSound's window to have the wrong  */
  11. /*           height in some instances.  Also extended DSound's Workbench*/
  12. /*           support:  DSound now recognizes a number of tool types      */
  13. /*           which give the user the same level of control as when      */
  14. /*           DSound is used from the Shell.                  */
  15. /*           July 18, 1994                          */
  16. /*    V1.40  - Fixed a bug that caused slowdowns with floptical drives,   */
  17. /*           added some Workbench support (a project with "DSound" as   */
  18. /*           its default tool can now be run by double-clicking on its  */
  19. /*           icon), and added an ARexx port so now one can quit DSound  */
  20. /*           via an ARexx command.  In addition, DSound is no longer      */
  21. /*           pure (i.e. can not be made resident), due to conflicts     */
  22. /*           with MinRexx.                          */
  23. /*           July 2, 1994                          */
  24. /*    V1.31  - Fixed some bugs that caused some samples (esp. ones        */
  25. /*           without a CHAN chunk) to not play.              */
  26. /*           March 6, 1994                          */
  27. /*    V1.30  - DSound now displays the name of the sound sample being      */
  28. /*           played, the number of seconds of the sample that have been */
  29. /*           played, and the total number of seconds in the sample.      */
  30. /*           A bug that prevent DSound from being aborted from the      */
  31. /*           window when a stereo sample is played has also been fixed. */
  32. /*           July 17, 1993                          */
  33. /*    V1.20  - Added the ability to stop DSound by typing CTRL-C, and      */
  34. /*           added the switch '-w', which keeps the DSound window from  */
  35. /*           opening.                           */
  36. /*           August 23, 1992                          */
  37. /*    V1.10  - Added the ability to play a sound sample repeatedly (in a  */
  38. /*           loop).                              */
  39. /*           July 11, 1992                          */
  40. /*    V1.00  - Added a new module (Mem.c) which allows a sample to be     */
  41. /*           loaded entirely into memory, so samples can be played from */
  42. /*           floppy disk without first copying to a hard or RAM drive.  */
  43. /*           DSound also can now play a single channel of a stereo      */
  44. /*           out of two speakers.  The small window, used to let the      */
  45. /*           user abort a playing sample, as been redone (DSound also   */
  46. /*           now responds instantly when the user clicks on the Close   */
  47. /*           gadget).  DSound now checks a given 8SVX sample to make      */
  48. /*           sure that it is actually a valid sample.  Finally, DSound  */
  49. /*           has been made pure (residentiable).                        */
  50. /*           Second release (April 16, 1992)                            */
  51. /*    V0.94a - Can now play a mono sample out of both speakers at the      */
  52. /*           same time (using the -2 switch).                           */
  53. /*           March 27, 1992 (a little later)                            */
  54. /*    V0.93a - Now handles stereo sound samples.  Either the right or      */
  55. /*           left, or both, stereo channels can be played.  Also split  */
  56. /*           off the code that actually plays the sound sample into a   */
  57. /*           separate source file (Play.c).                             */
  58. /*           March 27, 1992                          */
  59. /*    V0.92a - Now gets the length of the sound sample from the head of   */
  60. /*           the BODY chunk, instead of the VHDR (a workaround to a bug */
  61. /*           in the Perfect Sound software that would sometimes store   */
  62. /*           an incorrect length in the VHDR chunk of a sound sample).  */
  63. /*           November 4, 1991                       */
  64. /*    V0.91a - First release (September 11, 1991)                         */
  65. /**************************************************************************/
  66.  
  67. #include <exec/types.h>
  68. #include <exec/exec.h>
  69. #include <devices/audio.h>
  70. #include <dos/dos.h>
  71. #include <intuition/intuition.h>
  72. #include <intuition/intuitionbase.h>
  73. #include <graphics/gfxbase.h>
  74. #include <workbench/startup.h>
  75. #include <stdlib.h>
  76. #include <stdio.h>
  77. #include <string.h>
  78.  
  79. #include "dsound.h"
  80. #include "arexx.h"
  81. #include "minrexx.h"
  82.  
  83. #include <proto/intuition.h>
  84. #include <proto/graphics.h>
  85. #include <proto/exec.h>
  86. #include <proto/dos.h>
  87. #include <proto/icon.h>
  88.  
  89. #include <pragmas/intuition_pragmas.h>
  90. #include <pragmas/graphics_pragmas.h>
  91. #include <pragmas/exec_pragmas.h>
  92. #include <pragmas/dos_pragmas.h>
  93.  
  94. char filename[256];
  95.  
  96. #define DEF_BUF_SIZE 0xFFFFFFFF
  97.  
  98. void InterpretArgs(int argc,char *argv[]);
  99. void InterpretWBArgs(struct WBArg *wbArgs);
  100. BOOL LoopAndNoWindow_WB(void);
  101. void showAboutWindow(void);
  102. BOOL noFilter=FALSE;
  103. UBYTE volume=0;
  104. UWORD speed=0;
  105. ULONG bufSize=DEF_BUF_SIZE;
  106.  
  107. void filter_on(void);
  108. void filter_off(void);
  109. char *getDoubleDigit(unsigned int value,char *buf);
  110.  
  111. char *version="$VER: DSound V1.50 (18.7.94)";
  112. char *copyright="Copyright 1991-1994 by Dave Schreiber, All Rights Reserved";
  113.  
  114. extern struct IntuitionBase *IntuitionBase;
  115. struct GfxBase *GfxBase=NULL;
  116. extern struct Library *IconBase;
  117.  
  118. struct Window *window=NULL;
  119.  
  120. BPTR file=NULL;
  121.  
  122. channel audioChannel=UNSPECIFIED;
  123. BOOL bothChan=FALSE;
  124. BOOL readAll=FALSE;
  125. BOOL loop=FALSE;
  126. BOOL titleBarName=TRUE;
  127. BOOL titleBarTime=TRUE;
  128.  
  129. /*The window definition*/
  130. struct NewWindow newWindow = {
  131.     0,0,
  132.     60,56,
  133.     0,1,
  134.     CLOSEWINDOW,
  135.     SMART_REFRESH|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE,
  136.     NULL,
  137.     NULL,
  138.     "DSound V1.50",
  139.     NULL,
  140.     NULL,
  141.     5,5,
  142.     640,200,
  143.     WBENCHSCREEN
  144. };
  145.  
  146. /*This determines whether or not the window will be opened*/
  147. BOOL openTheWdw=TRUE;
  148. ULONG signalMask=SIGBREAKF_CTRL_C;
  149.  
  150. struct TextFont *titleBarFont=NULL;
  151. long arexxSigBit=0;
  152.  
  153. extern struct WBStartup *WBenchMsg;
  154.  
  155. main(int argc,char *argv[])
  156. {
  157.    struct Voice8Header vhdr;
  158.    UBYTE foo2[5];
  159.    UBYTE foo[5];
  160.    ULONG chan;
  161.    ULONG sampleLength;
  162.    ULONG lock;
  163.    ULONG titleLength,nameLength,timeLength,colonLength,finalDelta;
  164.    char *chanStr;
  165.  
  166.    filename[0]=NULL;
  167.  
  168.    /*If run from the CLI*/
  169.    if(WBenchMsg==NULL)
  170.    {
  171.       /*Get and interpret the command-line arguments*/
  172.       InterpretArgs(argc,argv);
  173.    }
  174.    else
  175.    {
  176.       if(WBenchMsg->sm_NumArgs>0)
  177.      InterpretWBArgs(&WBenchMsg->sm_ArgList[0]);
  178.  
  179.       if(WBenchMsg->sm_NumArgs>1)
  180.       {
  181.      CurrentDir(WBenchMsg->sm_ArgList[1].wa_Lock);
  182.      InterpretWBArgs(&WBenchMsg->sm_ArgList[1]);
  183.      if(loop && openTheWdw==FALSE)
  184.         if(!LoopAndNoWindow_WB())
  185.            exit(0);
  186.      strcpy(filename,WBenchMsg->sm_ArgList[1].wa_Name);
  187.       }
  188.       else
  189.       {
  190.      showAboutWindow();
  191.      exit(0);
  192.       }
  193.    }
  194.  
  195.    /*Exit if there was no sound sample specified*/
  196.    if(filename[0]==NULL)
  197.    {
  198.       WriteMsg("Please specify the name of a sound sample\n");
  199.       cleanup(75);
  200.    }
  201.  
  202.    /*Open the file*/
  203.    file=Open(filename,MODE_OLDFILE);
  204.    if(file==NULL)
  205.    {
  206.       WriteMsg("Couldn't open the file\n");
  207.       cleanup(100);
  208.    }
  209.  
  210.    arexxSigBit=initRexxPort();
  211.  
  212.    /*If the user hasn't told us not to open the window*/
  213.    if(openTheWdw)
  214.    {
  215.       char temp[256];
  216.       int yDelta=0;
  217.       /*Open libraries*/
  218.       GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L);
  219.  
  220.       if(GfxBase==NULL || IntuitionBase==NULL)
  221.       {
  222.      WriteMsg("A shared library could not be opened\n");
  223.      cleanup(50);
  224.       }
  225.  
  226.       /*Get the size of the title bar font in a rather illegal way        */
  227.       /*Note:  programmers at C= should put a GetDefTitleBarFontHeight()    */
  228.       /*function into Intuition before complaining to me about the following*/
  229.       /*code.                                    */
  230.  
  231.       lock=LockIBase(0L);
  232.       newWindow.Height=IntuitionBase->ActiveScreen->Font->ta_YSize+3;
  233.       UnlockIBase(lock);
  234.  
  235.       window=OpenWindow(&newWindow);
  236.  
  237.       if(window->WScreen->Font->ta_YSize+3!=window->Height)
  238.      yDelta=window->WScreen->Font->ta_YSize+3-window->Height;
  239. /*       SizeWindow(window,0,window->WScreen->Font->ta_YSize+3-window->Height);*/
  240.  
  241.       if(window==NULL)
  242.      cleanup(110);
  243.       signalMask|=1<<window->UserPort->mp_SigBit;
  244.  
  245.       titleBarFont=OpenFont(IntuitionBase->ActiveScreen->Font);
  246.       if(titleBarFont==NULL)
  247.      cleanup(115);
  248.  
  249.       SetFont(window->RPort,titleBarFont);
  250.       finalDelta=titleLength=TextLength(window->RPort,"DSound V1.50",12);
  251.       colonLength=TextLength(window->RPort,":  ",3);
  252.       if(titleBarTime==FALSE)
  253.       {
  254.      timeLength=0;
  255.      if(titleBarName==FALSE)
  256.         colonLength=0;
  257.       }
  258.       else
  259.      timeLength=TextLength(window->RPort,"(00:00/00:00) ",14);
  260.  
  261.       if(titleBarName==FALSE)
  262.      nameLength=0;
  263.       else
  264.       {
  265.      strcpy(temp,"\"\"");
  266.      strcat(temp,filename);
  267.      nameLength=TextLength(window->RPort,temp,strlen(temp));
  268.       }
  269.  
  270.       if(60+finalDelta+nameLength+colonLength+timeLength >= window->WScreen->Width)
  271.       {
  272.      titleBarName=FALSE;
  273.      if(60+finalDelta+colonLength+timeLength >= window->WScreen->Width)
  274.      {
  275.         titleBarTime=FALSE;
  276.         if(60+titleLength >= window->WScreen->Width)
  277.            cleanup(199);
  278.      }
  279.      else
  280.         finalDelta+=(colonLength+timeLength);
  281.       }
  282.       else
  283.      finalDelta+=(colonLength+timeLength+nameLength);
  284.  
  285.       SizeWindow(window,finalDelta,yDelta);
  286.    }
  287.  
  288.    /*Read the header*/
  289.    Read(file,foo,4);
  290.    Seek(file,4,OFFSET_CURRENT);
  291.    Read(file,foo2,4);
  292.  
  293.    foo[4]=foo2[4]=NULL;
  294.  
  295.    /*Check the header's validity, more or less*/
  296.    if((strcmp(foo,"FORM")!=0) || (strcmp(foo2,"8SVX")!=0))
  297.    {
  298.       WriteMsg("Not a valid IFF 8SVX sound sample file.\n");
  299.       cleanup(120);
  300.    }
  301.  
  302.    if(strcmp(FindChunk(file,"VHDR"),"VHDR")!=0)
  303.    {
  304.       WriteMsg("Couldn't find the 8SVX header (VHDR).\n");
  305.       cleanup(130);
  306.    }
  307.  
  308.    /*Skip past the chunk size*/
  309.    Seek(file,4,OFFSET_CURRENT);
  310.  
  311.    /*Get the VHDR*/
  312.    Read(file,&vhdr,sizeof(struct Voice8Header));
  313.  
  314.    /*If no buffer size was specified, use a buffer that can hold 1 second*/
  315.    /*of sound*/
  316.    if(bufSize==0xFFFFFFFF)
  317.       bufSize=(vhdr.samplesPerSec+1)&(~1);
  318.  
  319.    /*Check for compression*/
  320.    if(vhdr.sCompression!=0)
  321.    {
  322.       WriteMsg("Can't play a compressed sample!\n");
  323.       cleanup(400);
  324.    }
  325.  
  326.    /*Get the CHAN chunk (which will tell us if the sample is stereo, or,*/
  327.    /*if it is mono, which speaker it should be played out of*/
  328.    chanStr=FindChunk(file,"CHAN");
  329.    if(strcmp(chanStr,"CHAN")==0)
  330.    {
  331.       /*Skip past chunk size*/
  332.       Seek(file,4,OFFSET_CURRENT);
  333.       Read(file,&chan,sizeof(long));
  334.  
  335.       /*The information we're looking for consists of one longword*/
  336.       switch(chan)
  337.       {
  338.      case 2:  /*Mono sample, left speaker*/
  339.         if(bothChan)
  340.            /*Play out of both channels if -2 used*/
  341.            audioChannel=MONO_BOTH;
  342.         else
  343.            if(audioChannel==UNSPECIFIED)
  344.           audioChannel=MONO_LEFT;
  345.         break;
  346.      case 4:  /*Mono sample, right speaker*/
  347.         if(bothChan)
  348.            /*Play out of both channels if -2 used*/
  349.            audioChannel=MONO_BOTH;
  350.         else
  351.            if(audioChannel==UNSPECIFIED)
  352.           audioChannel=MONO_RIGHT;
  353.         break;
  354.      case 6:     /*Stereo*/
  355.         switch(audioChannel)
  356.         {
  357.            /*This reconciles a user's choice with the fact that the*/
  358.            /*sample is in stereo*/
  359.  
  360.            /*Play left stereo channel*/
  361.            case MONO_LEFT:
  362.           if(bothChan)
  363.              audioChannel=STEREO_LEFT_BOTH;
  364.           else
  365.              audioChannel=STEREO_LEFT;
  366.           break;
  367.  
  368.            /*Play right stereo channel*/
  369.            case MONO_RIGHT:
  370.           if(bothChan)
  371.              audioChannel=STEREO_RIGHT_BOTH;
  372.           else
  373.              audioChannel=STEREO_RIGHT;
  374.           break;
  375.  
  376.            /*Play both channels*/
  377.            case UNSPECIFIED:
  378.           audioChannel=STEREO;
  379.           break;
  380.         }
  381.         break;
  382.       }
  383.    }
  384.    else
  385.    {
  386.       chan=0;
  387.       if(bothChan)
  388.      audioChannel=MONO_BOTH;
  389.    }
  390.  
  391.    /*Find the start of the BODY chunk*/
  392.    chanStr=FindChunk(file,"BODY");
  393.  
  394.    if(strcmp(chanStr,"BODY")!=0)
  395.    {
  396.       WriteMsg("Couldn't find body of sample.\n");
  397.       cleanup(140);
  398.    }
  399.  
  400.    if(noFilter)
  401.       filter_off();
  402.  
  403.    /*Get the length of the sample*/
  404.    Read(file,(char *)&sampleLength,4);
  405.  
  406.    SetSignal(0,0);
  407.  
  408.    /*Play the sample by choosing the appropriate player function*/
  409.    switch(audioChannel)
  410.    {
  411.       case MONO_LEFT:
  412.       case MONO_RIGHT:
  413.       case UNSPECIFIED:
  414.      /*Simple mono playback*/
  415.      playMonoSample(file,audioChannel,&vhdr,sampleLength);
  416.      break;
  417.       case MONO_BOTH:
  418.      /*Mono playback using both speakers*/
  419.      playMonoTwice(file,audioChannel,&vhdr,sampleLength);
  420.      break;
  421.       case STEREO_RIGHT:
  422.      /*Right stereo channel*/
  423.      audioChannel=MONO_RIGHT;
  424.      Seek(file,sampleLength/2,OFFSET_CURRENT);
  425.      playMonoSample(file,audioChannel,&vhdr,sampleLength/2);
  426.      break;
  427.       case STEREO_RIGHT_BOTH:
  428.      /*Right stereo channel out of both speakers*/
  429.      audioChannel=MONO_RIGHT;
  430.      Seek(file,sampleLength/2,OFFSET_CURRENT);
  431.      playMonoTwice(file,audioChannel,&vhdr,sampleLength/2);
  432.      break;
  433.       case STEREO_LEFT:
  434.      /*Left stereo channel*/
  435.      audioChannel=MONO_LEFT;
  436.      playMonoSample(file,audioChannel,&vhdr,sampleLength/2);
  437.      break;
  438.       case STEREO_LEFT_BOTH:
  439.      /*Left stereo channel out of both speakers*/
  440.      audioChannel=MONO_LEFT;
  441.      playMonoTwice(file,audioChannel,&vhdr,sampleLength/2);
  442.      break;
  443.       case STEREO:
  444.      /*Stereo sample (both channels)*/
  445.      playStereoSample(file,audioChannel,&vhdr,sampleLength/2,filename);
  446.      break;
  447.    }
  448.  
  449.    if(noFilter)
  450.       filter_on();
  451.  
  452.    /*Free allocated resources and exit*/
  453.    cleanup(0);
  454. }
  455.  
  456.  
  457.  
  458. /* Get an audio channel */
  459. struct IOAudio *GetAudioChannel(ULONG bufferSize,UBYTE *allocationMap)
  460. {
  461.    struct IOAudio *aIOB;
  462.    void *audioBuf;
  463.    struct Port *aPort;
  464.  
  465.    aPort=(struct Port *)CreatePort("dsound",0);
  466.    if(aPort==NULL)
  467.       return(NULL);
  468.  
  469.    /* Allocate the chip memory buffer for the channel */
  470.    audioBuf=(void *)AllocMem(bufferSize,MEMF_CHIP);
  471.    if(audioBuf==NULL)
  472.    {
  473.       DeletePort((struct MsgPort *)aPort);
  474.       return(NULL);
  475.    }
  476.  
  477.    /* Allocate an IOAudio structure*/
  478.    aIOB=(struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR);
  479.    if(aIOB==NULL)
  480.    {
  481.       DeletePort((struct MsgPort *)aPort);
  482.       FreeMem(audioBuf,bufferSize);
  483.       return(NULL);
  484.    }
  485.  
  486.    /* Set up the IOAudio to allocate the command channel */
  487.    aIOB->ioa_Request.io_Message.mn_Node.ln_Pri=0;
  488.    aIOB->ioa_Request.io_Message.mn_ReplyPort=(struct MsgPort *)aPort;
  489.  
  490.    aIOB->ioa_Data=allocationMap;
  491.    aIOB->ioa_Length=4;
  492.    aIOB->ioa_Request.io_Command=ADCMD_ALLOCATE;
  493.  
  494.    /*Open the audio device*/
  495.    OpenDevice("audio.device",0,(struct IORequest *)aIOB,0);
  496.  
  497.  
  498.    if(aIOB->ioa_AllocKey==0)
  499.    {  /*There was an error*/
  500.       DeletePort((struct MsgPort *)aPort);
  501.       FreeMem(audioBuf,bufferSize);
  502.       FreeMem(aIOB,sizeof(struct IOAudio));
  503.       return(NULL);
  504.    }
  505.    else
  506.    {
  507.       /* Set up the IOAudio for writes */
  508.       aIOB->ioa_Request.io_Command=CMD_WRITE;
  509.       aIOB->ioa_Request.io_Flags=ADIOF_PERVOL;
  510.       aIOB->ioa_Data=audioBuf;
  511.       aIOB->ioa_Length=bufferSize;
  512.       return(aIOB);
  513.    }
  514. }
  515.  
  516. /* Free an allocated audio channel */
  517. void FreeAudioChannel(struct IOAudio *aIOB)
  518. {
  519.    if(aIOB==NULL)
  520.       return;
  521.  
  522.    /* Free the audi obuffer */
  523.    if(aIOB->ioa_Data!=NULL)
  524.       FreeMem(aIOB->ioa_Data,aIOB->ioa_Length);
  525.  
  526.    /* Free the audio channel */
  527.    aIOB->ioa_Request.io_Command=ADCMD_FREE;
  528.    BeginIO((struct IORequest *)aIOB);
  529.    WaitIO((struct IORequest *)aIOB);
  530.    DeletePort(aIOB->ioa_Request.io_Message.mn_ReplyPort);
  531.  
  532.    /* Close the audio channel */
  533.    CloseDevice((struct IORequest *)aIOB);
  534.  
  535.    /* Free the IOAudio structure */
  536.    FreeMem(aIOB,sizeof(struct IOAudio));
  537.    return;
  538. }
  539.  
  540. /* Initialize an IOAudio's volume, period, and set the number of cycles */
  541. /* to one */
  542. void InitAudioChannel(struct IOAudio *aIOB,UWORD volume,UWORD period)
  543. {
  544.    aIOB->ioa_Period=period;
  545.    aIOB->ioa_Volume=volume;
  546.    aIOB->ioa_Cycles=1;
  547.    return;
  548. }
  549.  
  550. /* Duplicate an IOAudio structure */
  551. struct IOAudio *DuplicateAudioChannel(struct IOAudio *OrigIOB)
  552. {
  553.    struct IOAudio *aIOB;
  554.    void *audioBuf;
  555.  
  556.    if(OrigIOB==NULL)
  557.       return(NULL);
  558.  
  559.    /* Allocate the alternate buffer */
  560.    audioBuf=(void *)AllocMem(OrigIOB->ioa_Length,MEMF_CHIP);
  561.    if(audioBuf==NULL)
  562.       return(NULL);
  563.  
  564.    /*Allocate the IOAudio structure*/
  565.    aIOB=(struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR);
  566.    if(aIOB==NULL)
  567.    {
  568.       FreeMem(audioBuf,OrigIOB->ioa_Length);
  569.       return(NULL);
  570.    }
  571.  
  572.    /*Copy the original IOAudio's contents to the new one*/
  573.    CopyMem(OrigIOB,aIOB,sizeof(struct IOAudio));
  574.  
  575.    /*Except for the buffer pointer, of course*/
  576.    aIOB->ioa_Data=audioBuf;
  577.  
  578.    return(aIOB);
  579. }
  580.  
  581. /*Delete a duplicated IOAudio*/
  582. void DeleteDuplication(struct IOAudio *aIOB)
  583. {
  584.    if(aIOB != NULL)
  585.    {
  586.       /* Free the memory for the buffer and IOAudio */
  587.       if(aIOB->ioa_Data != NULL)
  588.      FreeMem(aIOB->ioa_Data,aIOB->ioa_Length);
  589.       FreeMem(aIOB,sizeof(struct IOAudio));
  590.    }
  591.    return;
  592. }
  593.  
  594. /* Load an IOAudio's buffer from an open file */
  595. ULONG LoadAudioBuffer(BPTR file,struct IOAudio *aIOB,ULONG toRead)
  596. {
  597.    if(toRead==0)
  598.       return(0);
  599.  
  600.    if(file==0L)
  601.       getLeft(aIOB->ioa_Data);
  602.    else if(file==4L)
  603.       getRight(aIOB->ioa_Data);
  604.    else
  605.       aIOB->ioa_Length=Read(file,aIOB->ioa_Data,toRead);
  606.    return(aIOB->ioa_Length);
  607. }
  608.  
  609. /*Find the beginning of an IFF chunk.  This routine will search for that*/
  610. /*chunk's name, and if found, will leave the file cursor at the chunk size*/
  611. /*field.  If the chunk isn't found, the file cursor will be left at the*/
  612. /*size field of the BODY chunk, if there was one*/
  613. char *FindChunk(BPTR file,char *string)
  614. {
  615.    long len,actLen;
  616.    int origPos;
  617.    static char buf[5];
  618.    buf[4]=NULL;
  619.  
  620.    /* If we cannot find the chunk, seek the file pointer back to the */
  621.    /* place it started at */
  622.    origPos=Seek(file,0,OFFSET_CURRENT);
  623.  
  624.    actLen=Read(file,buf,4);
  625.    while(strcmp(string,buf)!=0 && strcmp(buf,"BODY")!=0 && actLen > 0)
  626.    {
  627.       Read(file,(char *)&len,4);
  628.       len=(len+1) & (~1);
  629.       Seek(file,len,OFFSET_CURRENT);
  630.       actLen=Read(file,buf,4);
  631.    }
  632.    if(strcmp(string,buf)!=0)
  633.       Seek(file,origPos,OFFSET_BEGINNING);
  634.  
  635.    return(buf);
  636. }
  637.  
  638. /* Interpret the command line arguments */
  639. void InterpretArgs(int argc,char *argv[])
  640. {
  641.    int i;
  642.  
  643.    for(i=1;i<argc;i++)
  644.    {
  645.       if(argv[i][0]=='-')
  646.      switch(argv[i][1])
  647.      {
  648.         /*Deactivate title bar filename*/
  649.         case 'n':
  650.         case 'N':
  651.            titleBarName=FALSE;
  652.            break;
  653.  
  654.         /*Deactivate title bar time*/
  655.         case 't':
  656.         case 'T':
  657.            titleBarTime=FALSE;
  658.            break;
  659.  
  660.         /* Read the entire sample into memory before playing */
  661.         case 'm':
  662.         case 'M':
  663.            readAll=TRUE;
  664.            break;
  665.  
  666.         /* Use the left channel */
  667.         case 'l':
  668.         case 'L':
  669.            audioChannel=MONO_LEFT;
  670.            break;
  671.  
  672.         /* Use the right channel */
  673.         case 'r':
  674.         case 'R':
  675.            audioChannel=MONO_RIGHT;
  676.            break;
  677.  
  678.         /*Play a mono sample out of both speakers*/
  679.         case '2':
  680.            bothChan=TRUE;
  681.            break;
  682.  
  683.         /* Switch off the low-pass filter while the sample is playing */
  684.         case 'f':
  685.         case 'F':
  686.            noFilter=TRUE;
  687.            break;
  688.  
  689.         /* Play a sample at a given speed */
  690.         case 's':
  691.         case 'S':
  692.            speed=atol(&argv[i][2]);
  693.            if(speed > 28000)
  694.           speed=0;
  695.            break;
  696.  
  697.         /* The volume at which the sample should be played */
  698.         case 'v':
  699.         case 'V':
  700.            volume=atol(&argv[i][2]);
  701.            if(volume > 64)
  702.           volume=0;
  703.            break;
  704.  
  705.         /* The size of the chip RAM buffers */
  706.         case 'b':
  707.         case 'B':
  708.            bufSize=(atol(&argv[i][2])+1)&(~1);
  709.            if(bufSize==0)
  710.           bufSize=DEF_BUF_SIZE;
  711.            break;
  712.  
  713.         /* Loop the sample */
  714.         case 'o':
  715.         case 'O':
  716.            loop=TRUE;
  717.            break;
  718.  
  719.         case 'w':
  720.         case 'W':
  721.            openTheWdw=FALSE;
  722.            break;
  723.      }
  724.       else if(argv[i][0]=='?')
  725.       {
  726.      /*On-line help*/
  727.      WriteMsg("DSound V1.50 ©1991-1994 by Dave Schreiber\n");
  728.      WriteMsg("Usage:\n");
  729.      WriteMsg("  DSound <options> <filename>\n");
  730.      WriteMsg("Where the options are:\n");
  731.      WriteMsg("  -l -- Play the sample using the left speaker\n");
  732.      WriteMsg("  -r -- Play the sample using the right speaker\n");
  733.      WriteMsg("  -2 -- Play the sample using both speakers\n");
  734.      WriteMsg("  -f -- Shut off the low-pass filter\n");
  735.      WriteMsg("  -m -- Load the entire sample into memory\n");
  736.      WriteMsg("  -o -- Play the sample continuously (loop)\n");
  737.      WriteMsg("  -w -- Do not open the DSound window\n");
  738.      WriteMsg("  -n -- Do not show the sample name in the window\n");
  739.      WriteMsg("  -t -- Do not show the sample times in the window\n");
  740.      WriteMsg("  -s<speed> -- Play the sample at the given speed (samples/sec)\n");
  741.      WriteMsg("  -v<volume> -- Play the sample at the given volume (0-64)\n");
  742.      WriteMsg("  -b<bufsize> -- Use a buffer of size <bufsize> (default is 30K)\n");
  743.      exit(0);
  744.       }
  745.       else     /*Otherwise, the argument is a filename */
  746.      strcpy(filename,argv[i]);
  747.    }
  748. }
  749.  
  750. /* Interpret Workbench arguments */
  751. void InterpretWBArgs(struct WBArg *wbArgs)
  752. {
  753.    struct DiskObject *myIcon;
  754.  
  755.    if(wbArgs->wa_Name!=NULL && (myIcon=GetDiskObject(wbArgs->wa_Name))!=NULL)
  756.    {
  757.       char *val;
  758.       char **toolArray=(char **)myIcon->do_ToolTypes;
  759.  
  760.       if((val=FindToolType(toolArray,"PLAYWINDOW"))!=NULL)
  761.       {
  762.      if(MatchToolValue(val,"YES"))
  763.         openTheWdw=TRUE;
  764.      else if(MatchToolValue(val,"NO"))
  765.         openTheWdw=FALSE;
  766.       }
  767.       if((val=FindToolType(toolArray,"TITLETIME"))!=NULL)
  768.       {
  769.      if(MatchToolValue(val,"YES"))
  770.         titleBarTime=TRUE;
  771.      else if(MatchToolValue(val,"NO"))
  772.         titleBarTime=FALSE;
  773.       }
  774.       if((val=FindToolType(toolArray,"TITLENAME"))!=NULL)
  775.       {
  776.      if(MatchToolValue(val,"YES"))
  777.         titleBarName=TRUE;
  778.      else if(MatchToolValue(val,"NO"))
  779.         titleBarName=FALSE;
  780.       }
  781.       if((val=FindToolType(toolArray,"READALL"))!=NULL)
  782.       {
  783.      if(MatchToolValue(val,"YES"))
  784.         readAll=TRUE;
  785.      else if(MatchToolValue(val,"NO"))
  786.         readAll=FALSE;
  787.       }
  788.       if((val=FindToolType(toolArray,"SPEAKER"))!=NULL)
  789.       {
  790.      if(MatchToolValue(val,"LEFT"))
  791.      {
  792.         audioChannel=MONO_LEFT;
  793.         bothChan=FALSE;
  794.      }
  795.      if(MatchToolValue(val,"RIGHT"))
  796.      {
  797.         audioChannel=MONO_RIGHT;
  798.         bothChan=FALSE;
  799.      }
  800.      if(MatchToolValue(val,"BOTH"))
  801.         bothChan=TRUE;
  802.      if(MatchToolValue(val,"DONTCARE"))
  803.      {
  804.         audioChannel=UNSPECIFIED;
  805.         bothChan=FALSE;
  806.      }
  807.       }
  808.       if((val=FindToolType(toolArray,"FILTER"))!=NULL)
  809.       {
  810.      if(MatchToolValue(val,"YES"))
  811.         noFilter=FALSE;
  812.      else if(MatchToolValue(val,"NO"))
  813.         noFilter=TRUE;
  814.       }
  815.       if((val=FindToolType(toolArray,"LOOP"))!=NULL)
  816.       {
  817.      if(MatchToolValue(val,"YES"))
  818.         loop=TRUE;
  819.      else if(MatchToolValue(val,"NO"))
  820.         loop=FALSE;
  821.       }
  822.       if((val=FindToolType(toolArray,"SPEED"))!=NULL)
  823.       {
  824.      speed=atoi(val);
  825.      if(speed > 28000)
  826.         speed=0;
  827.       }
  828.       if((val=FindToolType(toolArray,"VOLUME"))!=NULL)
  829.       {
  830.      volume=atol(val);
  831.      if(volume > 64)
  832.         volume=0;
  833.       }
  834.       if((val=FindToolType(toolArray,"BUFSIZE"))!=NULL)
  835.       {
  836.      bufSize=atol(val);
  837.      if(bufSize==0)
  838.         bufSize=DEF_BUF_SIZE;
  839.       }
  840.    }
  841. }
  842.  
  843.  
  844. /*Update the sample information in the DSound window's title bar*/
  845. /*This information can included the name of the sample, along with*/
  846. /*its length and amount played (both in seconds)*/
  847. void updateSampleInfo(unsigned int currentPos,unsigned int length,
  848.               unsigned int sampleRate)
  849. {
  850.    unsigned int currentSeconds,currentMinutes,totalSeconds,totalMinutes;
  851.    static char windowTitle[256];
  852.    char tempBuf[4][4];
  853.    static BOOL nameAlreadyDisplayed=FALSE;
  854.  
  855.    /*If the user wants neither the name nor time printed, do nothing*/
  856.    /*Also do nothing if the window isn't open*/
  857.    if((titleBarTime==FALSE && titleBarName==FALSE) || window==NULL)
  858.       return;
  859.  
  860.    /*Return if the user just wanted the name displayed, and it has been*/
  861.    if(titleBarTime==FALSE && nameAlreadyDisplayed==TRUE)
  862.       return;
  863.  
  864.    /*Beginning of the title*/
  865.    strcpy(windowTitle,"DSound V1.50:  ");
  866.  
  867.    /*If the user wants the sample name displayed, put it in the buffer*/
  868.    if(titleBarName)
  869.    {
  870.       nameAlreadyDisplayed=TRUE;
  871.       sprintf(&windowTitle[strlen(windowTitle)],"\"%s\" ",filename);
  872.  
  873.       /*The name has been (or will be shortly) displayed, so don't */
  874.       /*update it again if you don't have to */
  875.       nameAlreadyDisplayed=TRUE;
  876.    }
  877.  
  878.    /*Likewise for the time left and the total time*/
  879.    if(titleBarTime)
  880.    {
  881.       /*Get the total time*/
  882.       totalSeconds=(length)/sampleRate;
  883.       totalMinutes=totalSeconds/60;
  884.       totalSeconds-=totalMinutes*60;
  885.  
  886.       /*Get the current time*/
  887.       currentSeconds=(currentPos)/sampleRate;
  888.       currentMinutes=currentSeconds/60;
  889.       currentSeconds-=currentMinutes*60;
  890.  
  891.       /*Create the string that holds the time, and put it in the*/
  892.       /*title bar buffer*/
  893.       sprintf(&windowTitle[strlen(windowTitle)],"(%s:%s/%s:%s)",
  894.              getDoubleDigit(currentMinutes,tempBuf[0]),
  895.              getDoubleDigit(currentSeconds,tempBuf[1]),
  896.              getDoubleDigit(totalMinutes,tempBuf[2]),
  897.              getDoubleDigit(totalSeconds,tempBuf[3]));
  898.    }
  899.    Forbid();
  900.       /*Make sure that the screen isn't locked (e.g. holding down the*/
  901.       /*RMB will lock the screen), so that DSound will continue to */
  902.       /*play even if it can't update the title bar*/
  903.       if(window->WScreen->LayerInfo.Lock.ss_NestCount==0)
  904.      SetWindowTitles(window,windowTitle,NULL);
  905.    Permit();
  906.  
  907.    return;
  908. }
  909.  
  910. char *getDoubleDigit(unsigned int value,char *buf)
  911. {
  912.    if(value<10)
  913.       sprintf(buf,"0%d",value);
  914.    else
  915.       sprintf(buf,"%d",value);
  916.  
  917.    return(buf);
  918. }
  919.  
  920. /*Switch on the low-pass filter */
  921. void filter_on()
  922. {
  923.    *((char *)0x0bfe001)&=0xFD;
  924. }
  925.  
  926. /*Switch off the low-pass filter*/
  927. void filter_off()
  928. {
  929.    *((char *)0x0bfe001)|=0x02;
  930. }
  931.  
  932. struct EasyStruct erError1Line=
  933. {
  934.    sizeof(struct EasyStruct),
  935.    0,
  936.    "Program error:  DSound",
  937.    "%s",
  938.    "Ok"
  939. };
  940.  
  941. /*Write a message to the CLI*/
  942. void WriteMsg(char *errMsg)
  943. {
  944.    if(WBenchMsg==NULL)
  945.       Write(Output(),errMsg,strlen(errMsg));
  946.    else
  947.    {
  948.       char tmpBuf[256];
  949.       int len=strlen(errMsg);
  950.       strcpy(tmpBuf,errMsg);
  951.       if(tmpBuf[len-1]=='\n')
  952.      tmpBuf[len-1]=0;
  953.       EasyRequest(NULL,&erError1Line,NULL,tmpBuf);
  954.    }
  955. }
  956.  
  957. struct EasyStruct dontDoThat=
  958. {
  959.    sizeof(struct EasyStruct),
  960.    0,
  961.    "Program request:  DSound",
  962.    "Warning!\nWith looping enabled and\nno window, DSound will be\ndifficult to stop.",
  963.    "OK|Cancel"
  964. };
  965.  
  966. BOOL LoopAndNoWindow_WB(void)
  967. {
  968.    int result;
  969.    result=EasyRequest(NULL,&dontDoThat,NULL,NULL);
  970.    if(result==1)
  971.       return TRUE;
  972.    else
  973.       return FALSE;
  974. }
  975.  
  976. struct EasyStruct aboutDSound=
  977. {
  978.    sizeof(struct EasyStruct),
  979.    0,
  980.    "About DSound...",
  981.    "DSound V1.50\nJuly 18, 1994\n©1991-1994 by Dave Schreiber\nAll Rights Reserved.",
  982.    "OK"
  983. };
  984.  
  985. void showAboutWindow(void)
  986. {
  987.    EasyRequest(NULL,&aboutDSound,NULL,NULL);
  988.    return;
  989. }
  990.  
  991. /*Take a file handle and that handle's filename, and open that file again*/
  992. /*The position in the second file in set to the position in the first */
  993. /*file (so that the two file handles are essentially identical)*/
  994. /*This requires that the first file was opened in a shared mode, like */
  995. /*MODE_OLDFILE*/
  996. BPTR dupFileHandle(BPTR origFile,char *filename)
  997. {
  998.    BPTR dupFile;
  999.  
  1000.    dupFile=Open(filename,MODE_OLDFILE);
  1001.  
  1002.    if(dupFile==NULL)
  1003.       return(NULL);
  1004.  
  1005.    Seek(dupFile,getPosInFile(origFile),OFFSET_BEGINNING);
  1006.    return(dupFile);
  1007. }
  1008.  
  1009. /*Get the current position in a file*/
  1010. ULONG getPosInFile(BPTR file)
  1011. {
  1012.    LONG position;
  1013.  
  1014.    position=Seek(file,0,OFFSET_CURRENT);
  1015.    return((ULONG)position);
  1016. }
  1017.  
  1018. /* Free allocated resources */
  1019. void cleanup(int err)
  1020. {
  1021.    if(arexxSigBit!=0)
  1022.       dnRexxPort();
  1023.  
  1024.    /*If the entire sample was read into memory, this will delete whatever*/
  1025.    /*part of the sample still remains in memory*/
  1026.    deleteLeft();
  1027.    deleteRight();
  1028.  
  1029.    if(file!=NULL)
  1030.       Close(file);
  1031.  
  1032.    if(window!=NULL)
  1033.       CloseWindow(window);
  1034.  
  1035.    if(titleBarFont!=NULL)
  1036.       CloseFont(titleBarFont);
  1037.  
  1038.    if(GfxBase!=NULL)
  1039.       CloseLibrary((struct Library *)GfxBase);
  1040.  
  1041.    exit(err);
  1042. }
  1043.  
  1044. #ifdef LATTICE
  1045. int CXBRK(void) {return(0);}
  1046. int chkabort(void) {return(0);}
  1047. #endif
  1048.  
  1049. /*End of DSound.c*/
  1050.  
  1051.